/*
 * @Author: hc
 * @Date: 2024-03-06 19:45:42
 * @LastEditTime: 2024-03-07 17:53:59
 * @LastEditors: hc
 * @Description:
 */
import { DeleteOutlined, PlusSquareOutlined } from '@ant-design/icons';
import { Radio } from 'antd';
import { InternalNamePath } from 'antd/es/form/interface';
import { iup } from '../../../../util';
import { IFilterValue, ROW_PERMISSION_RELATION, ROW_PERMISSION_RELATION_TEXT, RulesControllerProps } from '../../types';
import './index.less';

// 行高
const ITEM_HEIGHT = 32;

// 间距
const MARGIN = 16;

// 存储对象节点的高度/线条高度等信息
const weakMap = new WeakMap();

export const RulesController = <T,>(props: RulesControllerProps<T>) => {
  const {
    value,
    disabled,
    maxLevel,
    maxSize,
    component,
    onAddCondition,
    onDeleteCondition,
    onChangeCondition,
    onChangeRowValues
  } = props;

  /**
   * 是否为条件节点
   */
  const isCondition = (item: IFilterValue<T>) =>
    item?.type && [ROW_PERMISSION_RELATION.AND, ROW_PERMISSION_RELATION.OR].includes(item?.type);

  /**
   * 计算每个节点的高度(height)/线条高度(lineHeight)/距离底部高度(bottom)
   */
  const calculateTreeItemHeight = (item: IFilterValue<T>, disabled: boolean) => {
    const composeDisabled = disabled || !!item.disabled;
    if (!item?.children) return weakMap.set(item, { height: ITEM_HEIGHT + MARGIN, lineHeight: ITEM_HEIGHT });
    item.children.map((child) => calculateTreeItemHeight(child, composeDisabled));
    const isLastCondition = !item.children.some(isCondition);
    const firstNodeIsCondition = isCondition(item.children[0]);
    // 编辑模式下计算
    if (!composeDisabled) {
      const height = item.children.reduce((prev, curr) => prev + weakMap.get(curr).height, ITEM_HEIGHT);
      let lineHeight;
      // 如果当前节点是最后的判断节点
      if (isLastCondition) {
        const firstNodeLineHeight = weakMap.get(item.children[0]).height - MARGIN;
        const lastNodeHeight = ITEM_HEIGHT;
        lineHeight = height - firstNodeLineHeight / 2 - lastNodeHeight / 2;
      } else {
        const firstNodeLineHeight = firstNodeIsCondition
          ? weakMap.get(item.children[0]).lineHeight / 2 + ITEM_HEIGHT / 2
          : ITEM_HEIGHT / 2 + MARGIN;
        lineHeight =
          firstNodeLineHeight +
          item.children?.slice(1).reduce((prev, curr) => prev + weakMap.get(curr).height, ITEM_HEIGHT / 2);
      }
      weakMap.set(item, { height, lineHeight });
    } else {
      const height = item.children.reduce((prev, curr) => prev + weakMap.get(curr).height, 0);
      let lineHeight;
      let bottom;
      // 如果当前节点是最后的判断节点
      if (isLastCondition) {
        lineHeight = height - ITEM_HEIGHT - MARGIN;
      } else {
        const firstNode = item.children[0];
        const lastNode = item.children[item.children.length - 1];
        const firstNodeLineHeight = weakMap.get(firstNode).height - getNodeReduceHeight(item, true);
        const lastNodeIsCondition = isCondition(lastNode);
        const reduceLastHeight = getNodeReduceHeight(item, false);
        const lastNodeLineHeight = weakMap.get(lastNode).height - MARGIN - reduceLastHeight;
        bottom = lastNodeIsCondition ? reduceLastHeight : ITEM_HEIGHT / 2;
        lineHeight =
          firstNodeLineHeight +
          item.children?.slice(1, -1).reduce((prev, curr) => prev + weakMap.get(curr).height, 0) +
          lastNodeLineHeight;
      }
      weakMap.set(item, { bottom, lineHeight, height });
    }
    return item;
  };

  /**
   * 获取节点高度
   */
  const getNodeReduceHeight = (item: IFilterValue<T>, isFirst: boolean): number => {
    const currentNode = isFirst ? item?.children?.[0] : item?.children?.[item?.children?.length - 1];
    if (!currentNode) return ITEM_HEIGHT / 2;
    const currentNodeIsCondition = isCondition(currentNode);
    if (currentNodeIsCondition) {
      return weakMap.get(currentNode)?.lineHeight / 2 + getNodeReduceHeight(currentNode, isFirst);
    }
    return ITEM_HEIGHT / 2;
  };

  /**
   * 条件渲染
   */
  const renderCondition = (item: IFilterValue<T>, namePath: InternalNamePath, disabled: boolean) => {
    const composeDisabled = disabled || !!item.disabled;

    // 渲染条件节点和线条
    if (item?.children?.length) {
      const childrenPath = (index: number) => {
        const newPath = [...namePath];
        newPath.push(...['children', index]);
        return newPath;
      };
      const { lineHeight, bottom } = weakMap.get(item);
      return (
        <div
          key={item.key}
          className={iup.classNames('ruleController__condition', {
            'ruleController__condition--active': item.children.length > 1
          })}
        >
          <div
            className={iup.classNames('condition__box', {
              disabled: composeDisabled
            })}
            style={{ height: lineHeight, bottom: bottom ?? MARGIN }}
          >
            <Radio.Group
              size="small"
              className="condition__box--radio"
              value={item?.type}
              buttonStyle="solid"
              onChange={(e) => !composeDisabled && onChangeCondition(item.key, item?.type as ROW_PERMISSION_RELATION)}
            >
              <Radio.Button value={ROW_PERMISSION_RELATION['AND']}>
                {ROW_PERMISSION_RELATION_TEXT[ROW_PERMISSION_RELATION.AND]}
              </Radio.Button>
              <Radio.Button value={ROW_PERMISSION_RELATION['OR']}>
                {ROW_PERMISSION_RELATION_TEXT[ROW_PERMISSION_RELATION.OR]}
              </Radio.Button>
            </Radio.Group>
            {item.children.length > 1 && (
              <span
                className={iup.classNames('condition__box--line', {
                  disabled
                })}
              />
            )}
          </div>
          {item.children.map((d: IFilterValue<T>, index: number) =>
            renderCondition(d, childrenPath(index), composeDisabled)
          )}
          {!composeDisabled && (
            <div className="condition__add">
              <span className="condition__add--line" />
              <span
                className={iup.classNames(
                  'condition__add--icon',
                  item?.children?.length >= maxSize ? 'condition__add--icon--disabled' : ''
                )}
                onClick={() => {
                  if (item?.children && item.children.length >= maxSize) return;
                  onAddCondition({
                    key: item.key,
                    isOut: true
                  });
                }}
              >
                新增条件组
              </span>
            </div>
          )}
        </div>
      );
    }
    // 渲染自定义的 component
    return (
      <div className="ruleController__item" key={item.key}>
        {value?.children && (
          <span
            className={iup.classNames('ruleController__item--line', {
              disabled
            })}
          />
        )}
        <div className="ruleController__item--component">
          {component({
            rowKey: item.key,
            disabled: composeDisabled,
            name: [...namePath, 'rowValues'],
            rowValues: item.rowValues as T,
            onChange: onChangeRowValues
          })}
        </div>
        {!composeDisabled && (
          <div className="ruleController__item--operation">
            <DeleteOutlined className="icon" onClick={() => onDeleteCondition(item.key)} />
            {item.level === maxLevel ? null : (
              <PlusSquareOutlined className="icon" onClick={() => onAddCondition({ key: item.key })} />
            )}
          </div>
        )}
      </div>
    );
  };

  if (!value) return null;

  calculateTreeItemHeight(value, !!disabled);

  return <div className="ruleController">{renderCondition(value, [], !!disabled || !!value.disabled)}</div>;
};
